package com.amkai.aes.webservice.binary.objecthandler;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;

import com.amkai.aes.aescommon.service.binary.job.ListJob;
import com.amkai.aes.generatedbeans.billingledger.details.SourceOfRevenue;
import com.amkai.aes.generatedbeans.common.Organization;
import com.amkai.aes.generatedbeans.dictionary.Item;
import com.amkai.aes.generatedbeans.insurance.InsuranceCarrier;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.organization.Enterprise;
import com.amkai.aes.generatedbeans.organization.Facility;
import com.amkai.aes.generatedbeans.passport.Passport;
import com.amkai.aes.generatedbeans.physstaff.Physician;
import com.amkai.aes.generatedbeans.procedure.Procedure;
import com.amkai.aes.server.organization.OrganizationManager;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.handlers.ListMode;

public class ListHandler implements JobObjectHandler<ListJob, Serializable, Serializable> {

	private static final Integer pageLines = 50;
	private Class<?> cls = null;
	private ListJob job;
	private static final Log log = LogFactory.getLog(ListHandler.class);



	public Serializable process(ListJob job, Serializable object) throws Exception {

		SessionManager sm = SiteManager.Start();

		String clazz = job.getClazz();
		ListMode mode = ListMode.values()[job.getListMode()];
		this.job = job;

		try {
			cls = Class.forName(clazz);

			if (clazz == null || mode == null) {
				log.debug("ERROR! Missing list job information!");
				return null;
			}

			switch(mode) {
			case LIST_SIZE: {
				Integer listSize = null;
				if(Department.class.isAssignableFrom(cls)) {
					listSize = ((Integer)sm.execute("select count(*) from Department d where (d.parent.id = "+job.getModuleDepartment().getParent().getId()+")").iterate().next()).intValue();
				} else if(Passport.class.isAssignableFrom(cls)) {
					String active = "";
					if (job.getActiveOnly()) {
						active = " and p.active = 1 ";
					}
					Long bgid = job.getModuleDepartment().getParent().getId();
					listSize = ((Integer)sm.execute("select count(*) from Passport p LEFT JOIN FETCH p.person where exists(select pbga.id from PassportBGAssociation as pbga where pbga.passport.id = p.id and pbga.businessGroup.id = "+bgid+")"+active).iterate().next()).intValue();
				} else {
					listSize = ((Integer)sm.execute("select count(*) from "+ clazz).iterate().next()).intValue();
				}
				if (listSize == null) return 0;
				return listSize.intValue();
			}
			case GET_LIST: {
				List<?> fullList = sm.execute(getQuery(cls, job, sm)).list();
				return fullList.toArray();
			}
			case GET_PAGE_AT:
				int pageIndex = job.getPageIndex();
				if (pageIndex < 0)
					pageIndex = 0;

				Query qr = sm.execute(getQuery(cls, job, sm));

				List<?> pageList = qr
				.setFirstResult(pageIndex)
				.setMaxResults(pageLines)
				.list();

				return pageList.toArray();
			case PAGE_LINES: {
				return pageLines;
			}
			default: {
				log.debug("ERROR! Undefined list mode!");
				return null;
			}
			}
		}
		catch (Exception ex) {
			log.error("",ex);
			throw ex;
		}
		finally {
			sm.closeSession();
		}

	}

	// KKORNEL: AES-4465
	//private final String ACTIVE_FILTER = "exists (from ItemAndDepartmentAssociation iada where iada.item = d and iada.baseOrganization.id = %d) ";
	private final String SHARED_ACTIVE_FILTER = "d.active = 1 AND (d.baseOrganization.id = %d OR d.baseOrganization.id = %d)";
	private String getActiveFilter(SessionManager sm) {

		//if (CommonSettings.USE_DATA_SHARING) {
		OrganizationManager manager = new OrganizationManager(sm);

		Enterprise enterprise = manager.getEnterprise();

		return String.format(SHARED_ACTIVE_FILTER, job.getModuleDepartment().getId(), enterprise.getId());
		/*}
		else {
			return String.format(ACTIVE_FILTER, job.getModuleDepartment().getId());
		}*/
	}

	private String getQuery(Class<?> cls, ListJob job, SessionManager sm) {
		if (cls == null) return null;
		if (Passport.class.isAssignableFrom(cls)) {

			String active = "";
			if (job.getActiveOnly()) {
				active = " and p.active = 1 ";
			}

			Long bgid = job.getModuleDepartment().getParent().getId();
			String q = "from Passport p LEFT JOIN FETCH p.person where exists(select pbga.id from PassportBGAssociation as pbga where pbga.passport.id = p.id and pbga.businessGroup.id = "+bgid+")"+active+ " order by p.name";
			return q;
//			return "FROM Passport p LEFT JOIN FETCH p.person" + active + " order by p.name";

			//AES-6247
		} else 
			if (Facility.class.isAssignableFrom(cls)) {
				Department dep = job.getModuleDepartment();

				String shared = "";
				if (job.getIncludeShared()) {
					shared = " or shared = 1 ";
				}

				return "FROM Facility WHERE parent = "+ dep.getId() + shared + " order by name";

				//AES-6247
			} else if (Organization.class.isAssignableFrom(cls)) {
				Department dep = job.getModuleDepartment();
				return "FROM Organization WHERE " +
				"baseOrganization = "+ dep.getId() +
				" order by description";
			} else if(Department.class.isAssignableFrom(cls)) {
				return "FROM Department d where (d.parent.id = "+job.getModuleDepartment().getParent().getId()+")";
			} else if (Item.class.isAssignableFrom(cls)) {

				String hql = "FROM "+ cls.getSimpleName() + " d ";

				// KKORNEL: AES-11533
				hql += " LEFT JOIN FETCH d.baseOrganization  ";

				if (Procedure.class.isAssignableFrom(cls)) {
					hql += " LEFT JOIN FETCH d.procedureCalcMethodEnumWrapper ";

				}
				if (InsuranceCarrier.class.isAssignableFrom(cls)) {
					hql += "LEFT JOIN FETCH d.mainInsuranceClaimOffice LEFT JOIN FETCH d.mainInsurancePlan ";
				}
				if (SourceOfRevenue.class.isAssignableFrom(cls)) {
					hql += "LEFT JOIN FETCH d.journalCodeForWriteOff ";
				}

				hql += "where " + getActiveFilter(sm);

				if (Physician.class.isAssignableFrom(cls)) {
					if (job.providerOnly)
						hql += " and (" + Physician.PROPERTYNAME_ISPROVIDER + " = true) ";
					else if (job.referringOnly) 
						hql += " and (" + Physician.PROPERTYNAME_ISREFERRING + " = true) ";
				}

				hql += "order by d." + Item.PROPERTYNAME_NAME;
				return hql;
			}

		return "from "+ cls.getSimpleName();
	}
}
